package com.system.demo.service.auth.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.system.demo.commonService.RedisService;
import com.system.demo.entity.auth.*;
import com.system.demo.entity.auth.DTO.AddRoleDTO;
import com.system.demo.entity.auth.DTO.MenuIdsDTO;
import com.system.demo.mapper.auth.SystemMenuMapper;
import com.system.demo.mapper.auth.SystemRoleMapper;
import com.system.demo.mapper.auth.SystemRoleMenuMapper;
import com.system.demo.service.auth.SystemRoleMenuService;
import com.system.demo.service.auth.SystemRoleService;
import com.system.demo.tool.ResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.system.demo.service.constant.RoleConstant.*;

@Service
public class SystemRoleServiceImpl implements SystemRoleService {


    @Autowired
    private SystemRoleMapper systemRoleMapper;

    @Autowired
    private SystemRoleMenuService systemRoleMenuService;
    
    @Autowired
    private SystemMenuMapper systemMenuMapper;

    @Autowired
    private SystemRoleMenuMapper systemRoleMenuMapper;

    @Autowired
    private RedisService redisService;

    @Override
    public ResponseResult<?> getTheNewestRoleTable() {
        List<SystemRole> systemRoles = systemRoleMapper.selectList(null);
        return ResponseResult.success("查询最新角色表成功",systemRoles.size(), systemRoles);
    }

    @Override
    @Transactional
    public ResponseResult<?> addRole(AddRoleDTO addRoleDTO) {
        //先判断这个角色 当前system_role中有没有
        if(Objects.equals(addRoleDTO.getRoleName(), "ROLE_ADMIN")){
            return ResponseResult.BadRequest("ROLE_ADMIN是管理员唯一标识！");
        }
        LambdaQueryWrapper<SystemRole> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SystemRole::getRoleDescription, addRoleDTO.getDescription());
        SystemRole systemRole1 = systemRoleMapper.selectOne(wrapper);
        if(systemRole1 != null){
            return ResponseResult.BadRequest("该角色已存在");
        }
        //查询最新的role_id 让新增的这个角色id为表中最大id加1 也相当于就是累加  这个功能做的有点丑 多担待
        Integer maxRoleId = systemRoleMapper.getMaxRoleId();

        // 新增角色到 system_role 表
        SystemRole systemRole = new SystemRole();
        systemRole.setRoleId(maxRoleId + ROLE_ID_INCREMENT_KEY);
        systemRole.setRoleName(addRoleDTO.getRoleName());
        systemRole.setRoleDescription(addRoleDTO.getDescription());
        systemRole.setIsAvailable(addRoleDTO.getIsAvailable());
        systemRole.setIsDefault(addRoleDTO.getIsDefault());
        systemRole.setCreateTime(LocalDateTime.now());
        systemRoleMapper.insert(systemRole);


        // 为角色绑定菜单，新增 system_role_menu 记录
        List<SystemRoleMenu> roleMenuList = addRoleDTO.getMenuIdList().stream()
                .map(menuId -> {
                    SystemRoleMenu roleMenu = new SystemRoleMenu();
                    roleMenu.setRoleId(maxRoleId + ROLE_ID_INCREMENT_KEY);
                    roleMenu.setMenuId(menuId);
                    return roleMenu;
                })
                .collect(Collectors.toList());
        systemRoleMenuService.batchInsertRoleMenu(roleMenuList);

        return ResponseResult.success("角色添加成功！");
    }

    @Override
    public ResponseResult<?> deleteRole(Integer roleId) {
        //将role的is_available设置成0就行了
        //先查询该角色是否已经不可用了
        if(roleId == ROLE_ADMIN  || roleId == ROLE_STUDENT){
            return ResponseResult.BadRequest("该角色不能被禁用");
        }

        //获取is_available为1的roleId
        List<Integer> availableRoleIds = systemRoleMapper.getAvailableRoleIds();
        if(!availableRoleIds.contains(roleId)){
            return ResponseResult.BadRequest("该角色未被启用");
        }

        //在禁用角色时，找到与该角色关联的用户，并删除这些用户在 Redis 中的 menuList 缓存。
        List<String> userIds  = systemRoleMapper.getUidByRoleId(roleId);
        // 清除用户的 Redis 缓存
        clearRoleRelatedCache(userIds);

        // 更新 is_available 字段为 0
        int updateResult = systemRoleMapper.updateIsAvailable(roleId, ROLE_IS_NOT_AVAILABLE);
        if (updateResult <= 0) {
            return ResponseResult.InternalServerError("更新角色状态失败");
        }
        return ResponseResult.success("角色禁用成功");
    }

    @Override
    @Transactional
    public ResponseResult<?> updateRoleMenuList(Integer roleId, MenuIdsDTO menuIdsDTO) {
        // 查询当前角色已绑定的菜单列表
        List<Integer> currentMenuIds = systemRoleMenuMapper.getMenuIdsByRoleId(roleId);
        List<String> menuIds = menuIdsDTO.getMenuIds();
        // 计算需要添加和删除的菜单
        List<Integer> newMenuIds = menuIds.stream()
                .map(Integer::valueOf)
                .collect(Collectors.toList());
        List<Integer> menusToAdd = newMenuIds.stream()
                .filter(menuId -> !currentMenuIds.contains(menuId))
                .collect(Collectors.toList());
        List<Integer> menusToRemove = currentMenuIds.stream()
                .filter(menuId -> !newMenuIds.contains(menuId))
                .collect(Collectors.toList());

        // 添加新的菜单绑定
        if (!menusToAdd.isEmpty()) {
            List<SystemRoleMenu> roleMenusToAdd = menusToAdd.stream()
                    .map(menuId -> {
                        SystemRoleMenu roleMenu = new SystemRoleMenu();
                        roleMenu.setRoleId(roleId);
                        roleMenu.setMenuId(menuId);
                        return roleMenu;
                    })
                    .collect(Collectors.toList());
            systemRoleMenuService.batchInsertRoleMenu(roleMenusToAdd);
        }

        // 删除不需要的菜单绑定
        if (!menusToRemove.isEmpty()) {
            int deletedCount = systemRoleMenuMapper.batchDeleteRoleMenus(roleId, menusToRemove);
            if (deletedCount != menusToRemove.size()) {
                // 记录未删除的菜单 ID
                List<Integer> failedToDelete = menusToRemove.subList(deletedCount, menusToRemove.size());
                throw new RuntimeException("删除菜单失败，未能删除的菜单ID：" + failedToDelete);
            }
        }
        //在修改角色menu后，找到与该角色关联的用户，并删除这些用户在 Redis 中的 menuList 缓存。
        List<String> userIds  = systemRoleMapper.getUidByRoleId(roleId);
        // 清除用户的 Redis 缓存
        clearRoleRelatedCache(userIds);

        return ResponseResult.success("角色菜单列表更新成功");
    }

    /**
     * 清理与角色关联的用户缓存
     *
     * @param userIds 用户 ID 列表
     */
    private void clearRoleRelatedCache(List<String> userIds) {
        for (String uid : userIds) {
            String menuListKey = "menu:" + uid;
            String roleListKey = "role:" + uid;
            redisService.deleteTokenKey(menuListKey); // 删除 Redis 中的 menuList
            redisService.deleteTokenKey(roleListKey); // 删除 Redis 中的 roleList
        }
    }

    @Override
    public ResponseResult<?> getUserMenuList() {
        // 查询所有菜单及其父子关系
        List<Map<String, Object>> menuConnections = systemMenuMapper.getAllMenuConnections();

        // 创建 ID -> MenuList 的映射
        Map<Integer, MenuList> menuMap = new HashMap<>();
        for (Map<String, Object> row : menuConnections) {
            Integer id = (Integer) row.get("id");
            String path = (String) row.get("path");
            String label = (String) row.get("label");
            String value = (String) row.get("value");

            // 初始化每个节点并设置 children 为 null（默认没有子节点）
            menuMap.putIfAbsent(id, new MenuList(id, null, label, path, value));
        }

        // 构建树结构
        List<MenuList> rootMenus = new ArrayList<>();
        for (Map<String, Object> row : menuConnections) {
            Integer id = (Integer) row.get("id");
            Integer parentId = (Integer) row.get("menu_father_id");

            MenuList menu = menuMap.get(id);
            if (parentId == null) {
                // 根节点
                rootMenus.add(menu);
            } else {
                // 添加到父节点的 children
                MenuList parent = menuMap.get(parentId);
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>()); // 初始化子节点列表
                    }
                    parent.getChildren().add(menu);
                }
            }
        }

        // 遍历根节点及其子树，设置空的 children 为 null
        for (MenuList rootMenu : rootMenus) {
            setNullForEmptyChildren(rootMenu);
        }

        return ResponseResult.success("获取系统MenuList成功",rootMenus);
    }

    @Override
    public ResponseResult<?> getMenuIdsForRole(Integer roleId) {
        // 调用 Mapper 方法
        List<Integer> menuIds = systemRoleMenuMapper.getMenuIdsByRoleId(roleId);

        // 返回结果
        return ResponseResult.success("该角色的menuIds集合",menuIds.size(),menuIds);
    }

    @Override
    @Transactional
    public ResponseResult<?> enableRole(Integer roleId) {
        // 查询角色是否存在
        SystemRole systemRole = systemRoleMapper.selectOne(new QueryWrapper<SystemRole>()
                .in("role_id", roleId));
        if(roleId == ROLE_ADMIN){
            return ResponseResult.BadRequest("管理员不能被操作");
        }
        if (systemRole == null) {
            return ResponseResult.BadRequest("角色不存在");
        }

        // 检查角色是否已启用
        if (systemRole.getIsAvailable() == ROLE_IS_AVAILABLE) {
            return ResponseResult.BadRequest("该角色已经处于启用状态");
        }

        //在启用角色时，找到与该角色关联的用户，并删除这些用户在 Redis 中的 menuList 缓存。
        List<String> userIds  = systemRoleMapper.getUidByRoleId(roleId);
        // 清除用户的 Redis 缓存  让用户登录的时候再去请求数据库 然后将最新的权限存进redis
        clearRoleRelatedCache(userIds);

        // 更新角色为启用状态
        int updateResult = systemRoleMapper.updateIsAvailable(roleId, ROLE_IS_AVAILABLE);
        if (updateResult <= 0) {
            throw new RuntimeException("启用角色失败");
        }


        return ResponseResult.success("角色启用成功");
    }

    /**
     * 遍历节点，设置没有子节点的 children 为 null
     */
    private void setNullForEmptyChildren(MenuList menu) {
        if (menu.getChildren() != null) {
            for (MenuList child : menu.getChildren()) {
                setNullForEmptyChildren(child);
            }
            // 如果子节点列表为空，设置为 null
            if (menu.getChildren().isEmpty()) {
                menu.setChildren(null);
            }
        }
    }

}

